package time;

import java.util.Arrays;
import java.io.Serializable;

public class VectorTimeStamp implements Serializable{
	
	private int[] vTimeStamp;
	private int pos=-1;
	
	public VectorTimeStamp(int n, int position){
		this.vTimeStamp = new int[n];
		this.pos = position;
	}
	
	public VectorTimeStamp(int[] ts, int position){
		vTimeStamp = ts;
		pos = position;
	}
	
	public boolean happenedBefore(VectorTimeStamp a){
		// if t_a < t_b, then a->b
		
		int[] aa = ((VectorTimeStamp)a).vTimeStamp;
		int equalCount = 0;
		for(int i=0; i<vTimeStamp.length; i++){
			if(aa[i]<vTimeStamp[i])
				return false;
			else if(aa[i] == vTimeStamp[i])
				equalCount++;
		}
		if(equalCount == vTimeStamp.length)
			return false;
		
		return true;
	}
	
	public boolean isEqual(VectorTimeStamp a){
		// if t_a < t_b, then a->b
		
		int[] aa = ((VectorTimeStamp)a).vTimeStamp;

		for(int i=0; i<vTimeStamp.length; i++){
			if(aa[i]<vTimeStamp[i] || aa[i]>vTimeStamp[i])
				return false;
		}
		
		return true;
	}
	
	public boolean isConcurrentWith(VectorTimeStamp a){
		if(a instanceof VectorTimeStamp){
			if(!this.happenedBefore(a)&&!a.happenedBefore(this))
				return true;
			else 
				return false;
		}else{
			throw new RuntimeException("VectorTimeStamps can only be compared with VectorTimeStamps");
		}
	}
	
	protected void increment(VectorTimeStamp a){
		VectorTimeStamp vTs = (VectorTimeStamp)a;
		int[] otherTS = vTs.getVectorTimeStamp();
		
		for(int i=0; i<vTimeStamp.length; i++){
			vTimeStamp[i] = Math.max(vTimeStamp[i], otherTS[i]);
		}
		this.vTimeStamp[this.pos]++;
	}

	// this version of increment only increments the counter at your own location
	protected void increment() {
		this.vTimeStamp[this.pos]++;
	}

	// return the int array that represents the vector timestamp
	public int[] getVectorTimeStamp(){
		return vTimeStamp;
	}

	// return the String representation of the VectorTimeStamp
	public String toString(){
		return Arrays.toString(vTimeStamp);
	}

	// the owner process' index
	public int getPos(){
		return this.pos;
	}

	// increment the counter at the particular index pos
	public void increment(int pos) {
		vTimeStamp[pos]++;
	}
	
	// return a deep copy of this VectorTimeStamp
	protected VectorTimeStamp clone() {
		VectorTimeStamp newTS = new VectorTimeStamp(this.vTimeStamp.length, this.pos);
		newTS.vTimeStamp = this.vTimeStamp.clone(); // clone the underlying int[]
		newTS.pos = this.pos;
		return newTS;
	}
}
